/*
 * REFThread.h
 *
 *  Created on: Apr 19, 2013
 *      Author: Lucifer
 */

#ifndef REFTHREAD_H_
#define REFTHREAD_H_

#include "SyncBlock.h"
#include "REFThreadEvent.h"
#include "ThreadException.h"

namespace BFX
{
class REFThread;

/**
 * Represents the method that executes on BFX::REFThread or BFX::REFThreadPool.
 */
typedef	BFX::Delegate<void (void)>	ThreadCallback;

//////////////////////////////////////////////////////////////////////////////

/**
 * Represents a callback method to be executed by a BFX::REFThread or BFX::REFThreadPool.
 */
class REFThreadCallback : public REFObject
{
public:
	/**
	 * Initializes an new instance of BFX::REFCallback class.
	 */
	REFThreadCallback();
	/**
	 * Initializes an new instance of BFX::REFRunnable class.
 	 * @param[in] callback The functor object to be invoked when this object begins running.
	*/
	REFThreadCallback(ThreadCallback callback);
	/**
	 * Destroys the BFX::REFRunnable object.
	 */
	virtual ~REFThreadCallback();

	/**
	 * This method uses to be called in that separately time or running thread.
	 */
	virtual void Run();

protected:
	ThreadCallback	m_fnCallback;
};

//////////////////////////////////////////////////////////////////////////////

/**
 * This class represents a OS thread object, uses to creates and controls a thread, sets its priority, and gets its
 * status.
 *
 */
class REFThread : public REFObject
{
public:
	/**
	 * Initializes a new instance of the BFX::REFThread class.
	 * the overridable method BFX::REFThread::Run() to be invoked when this thread begins executing.
	 */
	REFThread();

	/**
	 * Initializes a new instance of the the BFX::REFThread class.
	 * @param[in] pStart The pointer of BFX::REFCallback to be invoked when this thread begins executing.
	 */
	REFThread(REFThreadCallback* pStart);

	/**
	 * Initializes a new instance of the the BFX::REFThread class.
	 * @param[in] fnStart The functor object to be invoked when this thread begins executing.
	 */
	REFThread(ThreadCallback fnStart);

	/**
	 * Destroys the BFX::REFThread object.
	 */
	virtual ~REFThread();

	/**
	 * Starts the thread, causes the thread state to running.
	 */
	void Start();

	/**
	 * Raises a BFX::ThreadInterruptException in the thread on which it is invoked, to interrupts a thread that is in
	 * the Wait Sleep Join thread state.
	 */
	void Interrupt();

	/**
	 * Raises a BFX::ThreadAbortException in the thread on which it is invoked, to begin the process of terminating the
	 * thread. Calling this method usually terminates the thread.
	 */
	void Abort();
	/**
	 * Blocks the calling thread until a thread terminates or the specified time elapses,
	 * @param nMilliseconds The number of milliseconds to wait for the thread to terminate. The default -1 indicates an
	 * 		infinite timeout period.
	 * @return True if the thread has terminated; false if the thread has not terminated after the amount of time
	 * 		specified by the nMilliseconds has elapsed.
	 */
	bool Join(INT32 nMilliseconds = -1);

	/**
	 * Gets a unique identifier for the current thread.
	 * @return An integer that represents a unique identifier for this thread.
	 */
	long GetThreadId() const;

	/**
	 * Suspends the current thread for a specified time.
	 * @param[in] nMilliseconds The number of milliseconds for which the thread is blocked. Default zero (0) to indicate
	 * 		that this thread should be suspended to allow other waiting threads to execute; Specify Infinite to block
	 * 		the thread indefinitely.
	 */
	static void Sleep(INT32 nMilliseconds = 0);

	/**
	 * Gets the currently running thread.
	 * @return A BFX::REFThread object that is the representation of the currently running thread. Or NULL if the
	 * 		current thread not created by BFX::REFThread class.
	 */
	static REFThread* GetCurrentThread();

	/**
	 * Causes a thread to wait the number of times defined by the iterations parameter.
	 * @param[in] nIterations A number that defines how long a thread is to wait. Default value is 1.
	 *
	 */
	static void SpinWait(int nIterations = 1);

	/**
	 * Gets the number of logical processors.
	 * @return The number of logical processors.
	 */
	static int GetNumberOfProcessors();
	/**
	 * Gets a value indicating whether or not a thread belongs to the managed thread pool. 
	 */
	bool IsPoolThread() const
	{
		return m_bIsPoolThread;
	}

	/**
	 * Cleanup thread static resources.
	 */
	static void StaticCleanup();

protected:
	/*
	 * Initializes thread static / instance resources, such as thread slot; alert signals...etc.
	 */
	void Initialize();
	static void StaticInitialize();

	/*
	 * This is the backup startup routine.
	 * It's keeps blank, will be invokes when thread starting up and no external delegate specified. We can overrides
	 * this method in derived classes.
	 */
	virtual void Run();

	/*
	 * The basic mechanism to send thread immediate notifications. Currently uses by interrupts and aborts the target
	 * thread by other threads.
	 * @see BFX::REFThread::Interrupt(), BFX::REFThread::Abort().
	 */
	void Alert();

	 // This method to handle interruption internally.
	void HandleThreadInterrupt();

	 // This method to handle abortion internally.
	void HandleThreadAbort();

	// The helper methods called by BFX::REFThread::HandleThreadAbort() to sets thread state.
	void SetAbortInitiated();

	/*
	 * Provides a appropriate(interruptible) wait functionality called by framework.
	 * @see BFX::SyncBlock::Wait()
	 */
	bool DoAppropriateWait(SyncBlock* pSyncBlk, INT32 nMilliseconds);

	/*
	 * Throws alertable exceptions.
	 * @param bAbort True indicates throw abort exception, otherwise interrupt exception.
	 */
	void ThrowAlertable(bool bAbort);

#ifdef	_WIN32
	// The intermediate thread procedure, uses to suit for windows system. It's also initializes TLS data;
	// autorelease pool...etc.
	static UINT32 __stdcall IntermediateThreadProc(void* pContext);
	// The APC based alertable interrupt procedure.
	static void __stdcall UserInterruptAPC(ULONG_PTR dwData);
#else	//	_WIN32
	// The intermediate thread procedure, uses to suit for POSIX system. It's also initializes TLS data;
	// autorelease pool...etc.
	static void* IntermediateThreadProc(void* pContext);
	// The signal based alertable interrupt procedure.
	static void SignalInterruptProc(int nSignal);
#endif	//	!_WIN32

protected:
	// Thread states
	enum ThreadState
	{
		TS_Unknown = 0x00000000,		// threads are initialized this way
		TS_AbortInitiated = 0x00000001,	// set when abort is begun

		TS_Unstarted = 0x00000400,		// Thread has never been started
		TS_Dead = 0x00000800,			// Thread is dead

		TS_Interruptible = 0x02000000,	// sitting in a Sleep(), Wait(), Join()
		TS_Interrupted = 0x04000000,	// was awakened by an interrupt APC. !!! This can be moved to TSNC
	};

	// We distinguish interrupting a thread between Interrupt() and other usage.
	// For Interrupt() usage, we will interrupt an alertable wait using the same
	// rule as ReadyForAbort.  Wait in EH clause or CER region is not interrupted.
	// For other usage, we will try to Abort the thread.
	// If we can not do the operation, we will delay until next wait.
	enum ThreadInterruptMode
	{
		TI_Interrupt = 0x00000001,		// Requested by Interrupt()
		TI_Abort = 0x00000002,			// Requested by Abort()
	};

	friend class SyncBlock;
	friend class ThreadStateHolder;
	friend class REFThreadPool;
protected:
	// The TLS slot that we'll put this thread object in.
	static bool		s_bInitialized;
	static SpinLock	s_syncLock;

	HANDLE	m_hThread;			// this thread's ID
	bool	m_bIsPoolThread;	// this flag indicates this is a thread pool worker.

	REF<REFThreadCallback> m_pStart;

	// support for Interrupt() which breaks out of Waits(), Sleeps(), Joins()
	long	 m_lUserInterrupt;

	volatile long m_lState; // Bits for the state of the thread

#ifdef	_WIN32
	static UINT32	s_dwTlsSlot;
	UINT32	m_nThreadId;
#else	// _WIN32
	static pthread_key_t	s_hTlsSlot;
	REF<REFThreadEvent>	m_pThreadEvent;
#endif	// _WIN32

};

} /* namespace BFX */

#endif /* REFTHREAD_H_ */
